iT邦幫忙

2023 iThome 鐵人賽

DAY 24
0
Modern Web

就是個Go,我也可以啦!GOGO系列 第 24

2023鐵人賽Day 24 Go X 百家爭鳴的router

  • 分享至 

  • xImage
  •  

決定路由的因素

一個好的路由應該由哪些因素決定呢,我們以下說明

  • 中間件 (Middlewares)
    • 我在理解middlewares時,我總覺得他就很像鈎子與回調函數,在處理某些事情前先處理某些事
    • 以web框架為例,當一個http請求到達伺服器時,他會先經過中間件進行處理,再到主要的請求處理器,這個中間件可以處理很多事情,像是檢查用戶登入,紀錄每次請求
    • 除此之外,當請求處理完成,再吐出response之前也可以經過中間件進行處理
    • 中間件與回調函數都提供一種方式,允許開發人員插入或掛鉤自定義功能和行為,而不用修改主要的業務邏輯
  • 錯誤處理 (Error Handling)
    • 當遇到一個沒有註冊的路徑時,我們需要發送一個錯誤的回應404
    • 良好的錯誤處理不僅能提供有用的錯誤消息給client端,還可以避免程序崩潰或出現不可預測的行為
  • 路由優先順序 (Routes Priority)
    • 路由優先順序確定了當多個路由可以匹配同一HTTP請求時,哪一個路由應該被選擇,對於請求/users/123,路由/users/static和/users/:id都可能匹配,通過確定路由優先順序,路由器可以確定應該選擇哪一個路由
  • net/http API
    • net/http是Go語言的標準庫中用於HTTP通信的套件,一個路由器與net/http兼容意味著它可以與Go的標準HTTP工具和套件一起使用,使得整合其他Go庫或框架變得更加容易

基本路由

最基本的路由,其實已經看過很多次了,是由 net/http 提供的

http.HandleFunc("/", HomeHandler)

net/http 提供了基本的路由功能,對於簡單的應用來說,net/http 包提供的功能可能就足夠了,但對於更複雜的應用,你可能會發現第三方的路由庫(例如 gorilla/mux 或 chi)提供了一些額外的功能和靈活性,這在 net/http 包中可能不容易實現

所以,才會有現在路由百家爭鳴的情況,在選擇路由時我們就要好好的比較

路由比較

https://ithelp.ithome.com.tw/upload/images/20231009/20150980ZLU7cFQAjW.jpg

使用 gorilla/mux

支援自定義路由/ 定義domain

先來個基本應用

r := mux.NewRouter()
r.HandleFunc("/articles/{articleID}", ArticleHandler)

再來要發揮他的優勢,自定義,可以定義哪些呢

  • 定義domain跟變動的subdomain
    r := mux.NewRouter()
    // Only matches if domain is "www.example.com".
    r.Host("www.example.com")
    // Matches a dynamic subdomain.
    r.Host("{subdomain:[a-z]+}.example.com")
    
  • HTTP方法約束
    r := mux.NewRouter()
    r.HandleFunc("/articles", CreateArticleHandler).Methods("POST")
    r.HandleFunc("/articles", GetAllArticlesHandler).Methods("GET")
    
  • 查詢參數路由
    r := mux.NewRouter()
    r.HandleFunc("/articles", ArticleHandler).Queries("type", "{type}")
    
    這個路由規則只有當請求的查詢參數包含 type 時才會匹配

使用 Chi

簡單使用

package main

import (
	"fmt"
	"net/http"
	"github.com/go-chi/chi"
)

func main() {
	r := chi.NewRouter()

	// 定義一個單一的路由
	r.Get("/", HomeHandler)

	// 啟動伺服器
	http.ListenAndServe(":8080", r)
}

// HomeHandler 是一個HTTP處理程序,它返回一個歡迎消息
func HomeHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprint(w, "Welcome to the Home Page!")
}

衝突路徑

package main

import (
	"fmt"
	"net/http"
	"github.com/go-chi/chi"
)

func main() {
	r := chi.NewRouter()

	// 定義一個正則表達式路由
	r.Get("/{userID:[0-9]+}", UserHandler)

	// 定義一個可能與上面的路由衝突的路由
	r.Get("/{username:[a-zA-Z]+}", UsernameHandler)

	// 啟動伺服器
	http.ListenAndServe(":8080", r)
}

// UserHandler 處理/userID路由,其中userID必須是數字
func UserHandler(w http.ResponseWriter, r *http.Request) {
	userID := chi.URLParam(r, "userID")
	fmt.Fprintf(w, "You are viewing user %s", userID)
}

// UsernameHandler 處理/username路由,其中username必須是字母
func UsernameHandler(w http.ResponseWriter, r *http.Request) {
	username := chi.URLParam(r, "username")
	fmt.Fprintf(w, "You are viewing the profile of %s", username)
}

在這個例子中,如果用戶輸入的URL是 /12345,它會匹配到 /{userID:[0-9]+},如果用戶輸入的URL是 /john,它會匹配到 /{username:[a-zA-Z]+}

但是,如果用戶輸入的URL是 /john123,這就創建了一個衝突的情況,因為這個字符串同時包含字母和數字,所以它既可以被視為一個用戶名也可以被視為一個用戶ID,在這種情況下,chi 會選擇第一個定義的路由,也就是 /{userID:[0-9]+},即使這個字符串更像一個用戶名

使用middleware

package main

import (
	"fmt"
	"net/http"
	"github.com/go-chi/chi"
	"github.com/go-chi/chi/middleware"
)

func main() {
	r := chi.NewRouter()

	// 使用一些中間件
	r.Use(middleware.Logger) // 日誌中間件,用於記錄所有請求的信息
	r.Use(middleware.Recoverer) // Recoverer中間件用於捕獲可能的panic並防止程序崩潰

	// 定義路由
	r.Get("/", HelloWorldHandler)

	// 啟動伺服器
	http.ListenAndServe(":8080", r)
}

// HelloWorldHandler 是一個簡單的HTTP處理程序,它返回一個歡迎消息
func HelloWorldHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprint(w, "Hello, World!")
}

以上簡單介紹了該怎麼選擇路由,以及簡單的使用方式


上一篇
2023鐵人賽Day 23 Go X web 伺服器
下一篇
2023鐵人賽Day 25 數據艙門的星際對接:Go database/sql 的連接探索
系列文
就是個Go,我也可以啦!GOGO30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言